export const meta = {
  title: 'Authentication & Authorization',
  position: 120
}

## Overview


In this section, you'll learn how you can migrate your authentication functionality from the Graphcool Framework to Prisma.

## Authentication & Authorization with the Graphcool Framework

With the Graphcool Framework, authentication is implemented using [resolver functions](https://www.graph.cool/docs/reference/functions/resolvers-su6wu3yoo2). The GraphQL schema of the API is extended with dedicated mutations that provide signup and login functionality.

To achieve a cleaner architecture and better separation of concern, with Prisma this functionality is now moved into the _application layer_.

With the Graphcool Framework, authentication involved the following steps:

1. Define your signup and login resolver functions as schema extension on the `Mutation` type in your GraphQL schema
1. Provide the implementation of the resolver functions in JavaScript directly through the Graphcool Framework or use a webhook to invoke a function hosted by yourself
1. Connect the mutation definitions with the implementation by adjusting your service definition file

To secure data access and define permission rules, the Graphcool Framework used the concept of _permission queries_. Each API operation could be associated with one (or more) permission rules that would be checked before performing the operations.

## Authentication with Prisma

Prisma has a different [authentication](vw4d#authentication) concept than the Graphcool Framework. Rather than tying authentication to a permission system, Prisma only provides a simple token-based (think: _API Key_) system for accessing the Prisma API.

User authentication and permission rules are now implemented in the application layer of your GraphQL server. The `exists` function from the [`prisma-binding`](wer1) package serves a similar purpose as permissions queries inside the Graphcool Framework.

Another major change to the Graphcool Framework is that in Prisma you now generate the JWT tokens for your users yourself, rather than having them generated by `graphcool-lib`.

## Going from the Framework to Prisma

The following instructions assume you're using `graphql-yoga` as your GraphQL server and that your schema definition is written in SDL.

> To learn what the implementation authentication and permissions with Prisma looks like in practice, you can check out our examples: [auth](https://github.com/graphcool/prisma/tree/master/examples/auth) & [permissions](https://github.com/graphcool/prisma/tree/master/examples/permissions).

### Step 1: Migrate schema definitions

In your Graphcool Framework service, you might have had a schema extension defined that looks as follows:

```grapqhl
type Mutation {
  signupUser(email: String!, password: String!): SignupUserPayload
  authenticateUser(email: String!, password: String!): AuthenticateUserPayload
}

type SignupUserPayload{
  userId: ID!
  token: String!
}

type AuthenticateUserPayload {
  token: String!
}
```

The `signupUser` and `authenticateUser` mutations can be used for signup and login. The returned `token` is a JSON web token that's generated by `graphcool-lib` and can be sent in the `Authorization` HTTP header to authenticate requests against the API.

You can now move these definitions into the schema definition of your `graphql-yoga` server. Note that you can also get rid of one workaround that was required due to the limitation that resolver functions were not able to return model types.

Here is a suggestion for what your new defintion could look like in your GraphQL server:

```grapqhl
type Mutation {
  signup(email: String!, password: String!): AuthPayload
  login(email: String!, password: String!): AuthPayload
}

type AuthPayload {
  token: String!
  user: User!
}
```

### Step 2: Migrate resolver functions

Next, you need to implement the resolvers for the above defined `signup` and `login` mutations. In these resolvers, you're now generating a JWT token which you then return to your users. In the `signup` resolver, you also create a new node of the `User` type.

**auth.js**:

```js
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')

const auth = {
  async signup(parent, args, ctx, info) {
    const password = await bcrypt.hash(args.password, 10)
    const user = await ctx.db.mutation.createUser({
      data: { ...args, password },
    })

    return {
      token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET),
      user,
    }
  },

  async login(parent, { email, password }, ctx, info) {
    const user = await ctx.db.query.user({ where: { email } })
    if (!user) {
      throw new Error(`No such user found for email: ${email}`)
    }

    const valid = await bcrypt.compare(password, user.password)
    if (!valid) {
      throw new Error('Invalid password')
    }

    return {
      token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET),
      user,
    }
  },
}

module.exports = { auth }
```

**AuthPayload.js**:

```js
const AuthPayload = {
  user: async ({ user: { id } }, args, ctx, info) => {
    return ctx.db.query.user({ where: { id } }, info)
  },
}

module.exports = { AuthPayload }
```

### Step 3: Migrate permission rules

As mentioned before, the `exists` function of the `prisma-binding` package is the tool of choice for migrating your permission queries.

Assume you have the following data model defined for your Prisma service

```graphql
type User @model {
  id: ID! @unique
  name: String!
  posts: [Post!]!
}

type Post @model {
  id: ID! @unique
  title: String!
  author: User!
}
```

With the Graphcool Framework, to express that you only wanted the `author` of a `Post` to be able to update it, you'd have to associate the following permission query with the `updatePost` mutation:

```graphql
query ($user_id: ID!, $post_id: ID!) {
  SomePostExists(filter: {
    id: $post_id
    author: {
      id: $user_id
    }
  })
}
```

With Prisma, you'll need to perform the check inside the corresponding `updatePost` resolver in the application layer.

The implementation of the resolver could looks as follows:

```js
async function updatePost(parent, { id, title, text }, ctx, info) {
   // `getUserId` throws an error if the requesting user is not authenticated
  const userId = getUserId(ctx)

  // this expresses the same condition as the permission query above
  const requestingUserIsAuthor = await ctx.db.exists.Post({
    id,
    author: {
      id: userId,
    },
  })

  // only if the condition is true, the post is actually updated
  if (requestingUserIsAuthor) {
    return await ctx.db.mutation.updatePost({
      where: { id },
      data: { title, text },
    }, info)
  }
  throw new Error(
    'Invalid permissions, you must be an admin or the author of a post to update it',
  )
}
```

The `getUserId` function could be implemented as follows:

```js
function getUserId(ctx) {
  const Authorization = ctx.request.get('Authorization')
  if (Authorization) {
    const token = Authorization.replace('Bearer ', '')
    const { userId } = jwt.verify(token, process.env.APP_SECRET)
    return userId
  }

  throw new AuthError()
}

class AuthError extends Error {
  constructor() {
    super('Not authorized')
  }
}
```

It reads the `Authorization` field from the incoming HTTP header which contains a JWT. If the JWT is valid, if retrieves the `userId` from it, otherwise it throws an error.